#pragma once

#include <string>
#include <cstdint>

// trim from left
inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v")
{
	s.erase(0, s.find_first_not_of(t));
	return s;
}

// trim from right
inline std::string& rtrim(std::string& s, const char* t = " \t\n\r\f\v")
{
	s.erase(s.find_last_not_of(t) + 1);
	return s;
}

// trim from left & right
inline std::string& trim(std::string& s, const char* t = " \t\n\r\f\v")
{
	return ltrim(rtrim(s, t), t);
}

// copying versions

inline std::string ltrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
	return ltrim(s, t);
}

inline std::string rtrim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
	return rtrim(s, t);
}

inline std::string trim_copy(std::string s, const char* t = " \t\n\r\f\v")
{
	return trim(s, t);
}

/***********************************************************************/

// trim from left
inline std::wstring& ltrim(std::wstring& s, const wchar_t* t = L" \t\n\r\f\v")
{
	s.erase(0, s.find_first_not_of(t));
	return s;
}

// trim from right
inline std::wstring& rtrim(std::wstring& s, const wchar_t* t = L" \t\n\r\f\v")
{
	s.erase(s.find_last_not_of(t) + 1);
	return s;
}

// trim from left & right
inline std::wstring& trim(std::wstring& s, const wchar_t* t = L" \t\n\r\f\v")
{
	return ltrim(rtrim(s, t), t);
}

// copying versions

inline std::wstring ltrim_copy(std::wstring s, const wchar_t* t = L" \t\n\r\f\v")
{
	return ltrim(s, t);
}

inline std::wstring rtrim_copy(std::wstring s, const wchar_t* t = L" \t\n\r\f\v")
{
	return rtrim(s, t);
}

inline std::wstring trim_copy(std::wstring s, const wchar_t* t = L" \t\n\r\f\v")
{
	return trim(s, t);
}

void split(const std::wstring& str, const std::wstring& delim, std::vector<std::wstring>& parts);
void split(const std::string& str, const std::string& delim, std::vector<std::string>& parts);

bool isEmpty(const wchar_t* s);

/// <summary>	Turn the specified path into an absolute path. We then check if this folder exists,
/// 			and if so, we return the absolute path.</summary>
/// <param name="p">	The const wchar_t* to process.</param>
/// <returns>	The absolute path (if it was successfully determined), an empty string otherwise. </returns>
std::wstring realPath(const wchar_t* p);

class CStopWatch
{
private:
	LARGE_INTEGER start;
	LARGE_INTEGER stop;
	LARGE_INTEGER frequency;

	double LIToSecs(LARGE_INTEGER & L);
public:
	CStopWatch();
	void startTimer();
	void stopTimer();
	double getElapsedTime();
};

class CBenchmarkResult
{
private:
	std::uint32_t repeats;
	double totalTime;
public:
	CBenchmarkResult(std::uint32_t repeats, double totalTimeInSecs);

	double GetTimePerCall() const;
	
	std::uint32_t GetRepeats() const;
	double TotalTimeInSeconds() const;
};

CBenchmarkResult BenchmarkFunction(std::function<void()> func, uint32_t repeats);
